package kit.docker.web;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Record;
import com.docker.core.constant.MainConstant;
import com.docker.core.mvc.Remark;
import kit.docker.datetime.DateKit;
import kit.docker.redis.RedisKit;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class RequestKit {

    /**
     * @Param: [request]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/11/20 020 10:20
     */
    @Remark("获取request中json字符串的内容")
    public static String getReqJsonStr(HttpServletRequest request) {
        if ("GET".equals(request.getMethod())) {
            return getReqGetStr(request);
        } else {
            // POST
            return getReqPostStr(request);
        }
    }

    private static String getReqGetStr(HttpServletRequest request) {
        String queryString = request.getQueryString();
        if (StrKit.isBlank(queryString)) {
            return null;
        }
        return new String(queryString.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8).replaceAll("%22", "\"");
    }

    /**
     * @Param: [request]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/11/20 020 10:21
     */
    @Remark("获取 post 请求内容")
    public static String getReqPostStr(HttpServletRequest request) {
        try {
            byte[] buffer = getRequestPostBytes(request);
            if (buffer == null) {
                return null;
            }
            String charEncoding = request.getCharacterEncoding();
            if (charEncoding == null) {
                charEncoding = "UTF-8";
            }
            return new String(buffer, charEncoding);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static byte[] getRequestPostBytes(HttpServletRequest request) {
        try {
            int contentLength = request.getContentLength();
            if (contentLength < 0) {
                return null;
            }
            byte[] buffer = new byte[contentLength];
            for (int i = 0; i < contentLength; ) {
                int readlen = request.getInputStream().read(buffer, i, contentLength - i);
                if (readlen == -1) {
                    break;
                }
                i += readlen;
            }
            return buffer;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Map<String, String> getParamMap(HttpServletRequest request) {
        Map<String, String> map = new TreeMap<>();
        Enumeration<String> enume = request.getParameterNames();
        while (enume.hasMoreElements()) {
            String name = enume.nextElement();
            map.put(name, request.getParameter(name));
        }
        return map;
    }

    public static Map<String, String> getParamMap(HttpServletRequest request, String... ignoreParam) {
        return getParamMap(request, new ArrayList<>(Arrays.asList(ignoreParam)));
    }

    public static Map<String, String> getParamMap(HttpServletRequest request, List<String> ignoreParamList) {
        Map<String, String> map = new TreeMap<>();
        Enumeration<String> enume = request.getParameterNames();
        while (enume.hasMoreElements()) {
            String name = enume.nextElement();
            if (ignoreParamList.contains(name)) {
                continue;
            }
            map.put(name, request.getParameter(name));
        }
        return map;
    }

    /**
     * 对所有请求参数按照字段名的 ASCII 码从小到大排序（字典序），并且生成url参数串
     *
     * @param paramMap 请求参数Map对象
     * @return 排序后的参数字符串
     */
    public static String formatParamMapToString(Map<String, String> paramMap) {
        return formatParamMapToString(paramMap, false, false, false);
    }

    /**
     * 对所有请求参数按照字段名的 ASCII 码从小到大排序（字典序），并且生成url参数串
     *
     * @param paramMap 请求参数Map对象
     * @return 排序后的参数字符串
     */
    public static String formatParamMapToString(Map<String, String> paramMap, boolean addAlso) {
        return formatParamMapToString(paramMap, false, false, addAlso);
    }

    /**
     * 对所有请求参数按照字段名的 ASCII 码从小到大排序（字典序），并且生成url参数串
     *
     * @param paramMap 请求参数Map对象
     * @return 排序后的参数字符串
     */
    public static String formatParamMapToString(Map<String, String> paramMap, boolean keyToLower, boolean urlEncode) {
        return formatParamMapToString(paramMap, keyToLower, urlEncode, false);
    }

    /**
     * 对所有请求参数按照字段名的 ASCII 码从小到大排序（字典序），并且生成url参数串
     *
     * @param keyToLower 是否对key字母转小写
     * @param urlEncode  是否执行URLEncode
     * @return 排序后的参数字符串
     */
    public static String formatParamMapToString(Map<String, String> paramMap, boolean keyToLower, boolean urlEncode, boolean addAlso) {
        try {
            List<String> paramList = new ArrayList<>();
            for (String key : paramMap.keySet()) {
                paramList.add((keyToLower ? key.toLowerCase() : key) + "="
                        + (urlEncode ? URLEncoder.encode(paramMap.get(key), "utf-8") : paramMap.get(key)));
            }
            Collections.sort(paramList);
            StringBuilder beforeSign = new StringBuilder();
            if (addAlso) {
                for (String param : paramList) {
                    beforeSign.append(param).append("&");
                }
                return beforeSign.substring(0, beforeSign.lastIndexOf("&"));
            }
            for (String param : paramList) {
                beforeSign.append(param);
            }
            return beforeSign.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }


    /**
     * @Param: [request http请求]
     * @return: 请求的ip地址
     * @Author: ldl
     * @Create: 2020/07/01 001 14:43
     */
    @Remark("获取请求的ip地址")
    public static String getRequestIp(HttpServletRequest request) {
        try {
            String ipAddress = request.getHeader("x-forwarded-for");
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
                if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {
                    //根据网卡取本机配置的IP
                    InetAddress inet = null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                    ipAddress = inet.getHostAddress();
                }
            }
            //对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
            if (ipAddress != null && ipAddress.length() > 15) { //"***.***.***.***".length() = 15
                if (ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
            return ipAddress;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Param: [request http请求]
     * @return: 请求的uri
     * @Author: ldl
     * @Create: 2020/07/01 001 14:44
     */
    @Remark("获取请求的uri")
    public static String getRequestURI(HttpServletRequest request) {
        return request.getRequestURI();
    }

    /**
     * @Param: [strIP ip地址]
     * @return: ip地址归属地信息
     * @Author: ldl
     * @Create: 2020/07/01 001 14:44
     */
    @Remark("获取ip地址的归属地")
    public static String getAddressByBD2(String strIP) {
        if (StrKit.isBlank(strIP)) {
            return null;
        }
        try {
            URL url = new URL("http://opendata.baidu.com/api.php?query=" + strIP + "&co=&resource_id=6006&t=1433920989928&ie=utf8&oe=utf-8&format=json");
            URLConnection conn = url.openConnection();
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
            String line = null;
            StringBuffer result = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }
            reader.close();
            JSONObject jsStr = JSONObject.parseObject(result.toString());
            if ("0".equals(jsStr.getString("status"))) {
                JSONArray jsData = jsStr.getJSONArray("data");
                JSONObject data = jsData.getJSONObject(0);
                return data.getString("location");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Param: [target 接口路由, request http请求]
     * @return: void
     * @Author: ldl
     * @Create: 2020/07/01 001 15:11
     */
    @Remark("请求记录写入缓存")
    public static void saveLog(String target, HttpServletRequest request) {
        Record requestLog = new Record();
        requestLog.set("request_time", DateKit.getNowDateTime());
        requestLog.set("request_action", target);
        requestLog.set("request_method", request.getMethod());
        requestLog.set("request_ip", getRequestIp(request));
        Map<String, String> paramMap = getParamMap(request);
        requestLog.set("request_param", paramMap);
        requestLog.set("interact_tag", paramMap.get("interact_tag"));
        requestLog.set("request_app_id", StrKit.isBlank(paramMap.get("app_id")) ? paramMap.get("appId") : paramMap.get("app_id"));
        if (StrKit.notBlank(requestLog.getStr("request_app_id"), paramMap.get("token"))) {
//            InsideUserBean user = LoginRedis.getSessionUser(requestLog.getStr("request_app_id"), paramMap.get("token"));
//            requestLog.set("request_user_id", StrKit.notNull(user) ? user.getUser_id() : null);
        }
        RedisKit.lPush(MainConstant.REDIS_DOCKER, "request_log", JsonKit.toJson(requestLog));
    }

}
